package com.sixbro.data.elasticsearch.service.base;

import com.sixbro.data.elasticsearch.common.PageQuery;
import com.sixbro.data.elasticsearch.common.SortParam;
import com.sixbro.data.elasticsearch.util.CollectionUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * <p>
 *
 * </p>
 *
 * @author: Mr.Lu
 * @since: 2021-12-14 17:11
 */
public interface IESBaseService<T, ID> {
    /** 属性缓存 */
    Map<Class<?>, List<Field>> FIELD_CACHE = new ConcurrentHashMap<>();

    /**
     * 获取实体class类型
     * @return 实体clazz类型
     */
    default Class<T> getEntityClass() {
        return (Class<T>) (((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
    }

    /**
     * 获取实体所有属性（排除序列号属性）
     * @return 属性集合
     */
    default List<Field> getEntityAllField() {
        Class<T> entityClass = getEntityClass();

        if (FIELD_CACHE.get(entityClass) != null) {
            return FIELD_CACHE.get(entityClass);
        }

        Field[] currentFields = entityClass.getDeclaredFields();

        Class<? super T> superclass = entityClass.getSuperclass();

        List<Field> supperFields = new ArrayList<>();
        // 可能有多层继承
        while (!superclass.equals(Object.class)) {
            Field[] declaredFields = superclass.getDeclaredFields();

            Collections.addAll(supperFields, declaredFields);

            superclass = superclass.getSuperclass();
        }
        // 排除序列化字段
        List<Field> fieldList = Arrays.stream(currentFields).filter(f -> !"serialVersionUID".equalsIgnoreCase(f.getName())).distinct().collect(Collectors.toList());
        // 父类字段
        List<Field> superFieldList = supperFields.stream().filter(f -> !"serialVersionUID".equalsIgnoreCase(f.getName())).distinct().collect(Collectors.toList());

        if (CollectionUtils.isNotEmpty(superFieldList)) {
            fieldList.addAll(superFieldList);
        }

        FIELD_CACHE.put(entityClass, fieldList);

        return fieldList;
    }

    /**
     * 页面返回字段
     * @return 实体所有字段名称数组
     */
    default String[] returnFields() {
        List<Field> fieldList = getEntityAllField();

        String[] fields = new String[fieldList.size()];

        for (int i = 0; i < fieldList.size(); i++) {
            fields[i] = fieldList.get(i).getName();
        }

        return fields;
    }

    /**
     * 排序字段、排序方式设置
     * 默认按照创建时间倒叙排列
     * @param query 查询参数
     * @param <Q>   查询参数实体
     */
    default <Q extends PageQuery> List<SortParam> sortFields(Q query) {
        if (StringUtils.isEmpty(query.getSortField()) || StringUtils.isEmpty(query.getSortWay())) {
            return null;
        }

        SortParam sp = new SortParam();
        sp.setFieldName(query.getSortField());
        sp.setOrder(SortOrder.valueOf(query.getSortWay().toUpperCase()));
        return CollectionUtils.singleList(sp);
    }

    /**
     * 构建过滤条件
     */
    default <Q extends PageQuery> void buildFilterCondition(BoolQueryBuilder filter, Q queryParam) {
        // eg:
        // 带分词匹配
        // filter.must(QueryBuilders.matchQuery("xxx", query.getXxxx()));
        // 不分词匹配
        // filter.must(QueryBuilders.termQuery("xxx", query.getXxx()));
        // 范围匹配
        // filter.must(QueryBuilders.rangeQuery("createTime").gte(query.getCreateTime() + " 00:00:00"));
    }

    <S extends T> S save(S entity);

    <S extends T> Iterable<S> saveAll(Iterable<S> entities);

    Optional<T> findById(ID id);

    boolean existsById(ID id);

    Collection<T> findAll();

    Collection<T> findAllById(Collection<ID> ids);

    long count();

    void deleteById(ID id);

    void delete(T entity);

    void deleteAllById(Iterable<? extends ID> ids);

    void deleteAll(Collection<? extends T> entities);

    void deleteAll();

    Iterable<T> findAll(Sort sort);

    Page<T> findAll(Pageable pageable);

    /**
     * 模糊搜索
     * @param entity   请求实体
     * @param fields   查询字段名称
     * @param pageable 分页对象
     * @return 分页参数
     */
    Page<T> searchSimilar(T entity, @Nullable String[] fields, Pageable pageable);

    /**
     * 分页查询（自定义）
     * @param query 请求参数
     * @param <Q>   请求参数类型
     * @return 分页数据
     */
    <Q extends PageQuery> Page<T> search(Q query);

    /**
     * 分页查询（自定义）
     * @param query 请求参数
     * @param <Q>   请求参数类型
     * @return 数据总数
     */
    <Q extends PageQuery> Long count(Q query);

    /**
     * 分页查询（自定义）
     * @param query 请求参数
     * @param <Q>   请求参数类型
     * @return 数据总数
     */
    <Q extends PageQuery> List<T> list(Q query);

    /**
     * 分页查询（自定义）
     * @param query      请求参数
     * @param <Q>        请求参数类型
     * @param columnName 返回列名
     * @return 数据总数
     */
    <Q extends PageQuery> List<T> list(Q query, String... columnName);

    /**
     * 根据ID保存或者更新
     * @param entity 请求实体
     * @param <S>    实体类型
     */
    <S extends T> void update(S entity);

    /**
     * 根据ID保存或者更新
     * @param entity 请求实体
     * @param <S>    实体类型
     */
    <S extends T> void updateAndFlush(S entity);

    /**
     * 批量保存或者更新
     * @param entities 请求实体集合
     * @param <S>      实体类型
     */
    <S extends T> void update(Collection<S> entities);

    /**
     * 批量保存或者更新
     * @param entities 请求实体集合
     * @param <S>      实体类型
     */
    <S extends T> void updateAndFlush(Collection<S> entities);

    /**
     * 批量保存或者更新
     * @param entities 请求实体集合
     * @param <S>      实体类型
     */
    <S extends T> void saveOrUpdate(Collection<S> entities);
}
